package primetest.impl.dao;

import java.io.IOException;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;


import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import primetest.dto.DepartmentDto;
import primetest.dto.DoctorDto;
import primetest.impl.dao.DepartmentDao;
import primetest.impl.dao.DoctorDao;
import primetest.impl.dao.Transaction;
import primetest.impl.dao.UserRoleDao;

//@Stateless
public class DoctorDao implements Serializable {
	/**
	 *
	 */
	private static final long serialVersionUID = -5505443957086378631L;

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private DepartmentDao officeDao;
	private UserRoleDao userRoleDao;

	private static List<DoctorDto> allItems = null;
	private static HashMap<Integer, DoctorDto> map = null;
	private static HashMap<String, DoctorDto> map2 = null;
	private static AtomicInteger count = null;

	@Inject
	public DoctorDao(DepartmentDao officeDao, UserRoleDao userRoleDao){
		this.officeDao = officeDao;
		this.userRoleDao = userRoleDao;
	}


	public synchronized List<DoctorDto> getDoctorList(Transaction transaction) throws IOException {
		if (allItems != null) {
			return allItems;
		}
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;
		map = new HashMap<Integer, DoctorDto>();
		map2 = new HashMap<String, DoctorDto>();
		int cnt = 0;
		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(GET_ALL);
			resultSet = prepareStatement.executeQuery();

			allItems = new ArrayList<DoctorDto>();
			while (resultSet.next()) {
				DoctorDto userDto = makeDoctorrDto(transaction, resultSet);
				map.put(userDto.getSeq(), userDto);
				map2.put(userDto.getId(), userDto);
				if (userDto.getSeq() > cnt) {
					cnt = userDto.getSeq();
				}
			}
			allItems = new ArrayList<DoctorDto>(map.values());
			count = new AtomicInteger(++cnt);
			return allItems;
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}

	private DoctorDto makeDoctorrDto(Transaction transaction, ResultSet rs) throws SQLException, IOException {
		int cnt = 0;
		DoctorDto doctorDto = new DoctorDto(rs.getInt(++cnt), rs.getString(++cnt), rs.getString(++cnt), rs.getString(++cnt),
				rs.getInt(++cnt), officeDao.findDepartment(transaction, rs.getInt(++cnt)) , rs.getString(++cnt), rs.getString(++cnt), rs.getInt(++cnt),
				rs.getString(++cnt), rs.getString(++cnt), rs.getDate(++cnt), rs.getDate(++cnt), userRoleDao.getUserRoleList(transaction, rs.getString(2)));
		return doctorDto;
	}



	public DoctorDto findDoctor(Transaction transaction, String id) throws IOException {
		if(allItems == null){
			getDoctorList(transaction);
		}
		return map2.get(id);
	}


	public DoctorDto findDoctor(Transaction transaction, int seq) throws IOException {
		if(allItems == null){
			getDoctorList(transaction);
		}
		return map.get(seq);
	}



	public List<DoctorDto> getDoctorListByDepartment(Transaction transaction, int officeSeq) throws IOException {
		if(allItems == null){
			getDoctorList(transaction);
		}
		List<DoctorDto> items = new ArrayList<DoctorDto>();
		for (DoctorDto d : allItems) {
			if (d.getDepartmentDtoSeq() == officeSeq) {
				items.add(d);
			}
		}
		return items;
	}


	public void addDoctor(Transaction transaction, DoctorDto userDto) throws IOException {
		PreparedStatement preparedSatement = null;
		try {
			Connection connection = transaction.getResource(Connection.class);
			preparedSatement = connection.prepareStatement(INSERT_DOCTOR);
			userDto.setSeq(count.getAndIncrement());
			preparedSatement.setInt(1, userDto.getSeq());
			preparedSatement.setString(2, userDto.getId());
			preparedSatement.setString(3, userDto.getPassword());
			preparedSatement.setString(4, userDto.getName());
			preparedSatement.setInt(5, userDto.getGender());
			preparedSatement.setInt(6, userDto.getDepartmentDto().getSeq());
			preparedSatement.setString(7, userDto.getDegree());
			preparedSatement.setString(8, userDto.getUniversity());
			preparedSatement.setInt(9, userDto.getWorkType());
			preparedSatement.setString(10, userDto.getWorkDomain());
			preparedSatement.setString(11, userDto.getIntroduction());
			preparedSatement.setDate(12, userDto.getBirthDate());
			preparedSatement.setDate(13, userDto.getJoinHospitalDate());
			preparedSatement.executeUpdate();
			userRoleDao.addUserRole(transaction, userDto.getId(), userDto.getRoleList());
			map.put(userDto.getSeq(), userDto);
			map2.put(userDto.getId(), userDto);
			allItems.add(userDto);
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (preparedSatement != null) {
				try {
					preparedSatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}




	public void updateDoctor(Transaction transaction, DoctorDto userDto) throws IOException {
		PreparedStatement prepareStatement = null;
		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(UPDATE_DOCTOR);
			prepareStatement.setString(1, userDto.getPassword());
			prepareStatement.setString(2, userDto.getName());
			prepareStatement.setInt(3, userDto.getGender());
			prepareStatement.setInt(4, userDto.getDepartmentDto().getSeq());
			prepareStatement.setString(5, userDto.getDegree());
			prepareStatement.setString(6, userDto.getUniversity());
			prepareStatement.setInt(7, userDto.getWorkType());
			prepareStatement.setString(8, userDto.getWorkDomain());
			prepareStatement.setString(9, userDto.getIntroduction());
			prepareStatement.setDate(10, userDto.getBirthDate());
			prepareStatement.setDate(11, userDto.getJoinHospitalDate());
			prepareStatement.setInt(12, userDto.getSeq());
			prepareStatement.executeUpdate();
			userRoleDao.deleteUserRole(transaction, userDto.getId());
			if(userDto.getRoleList().size() > 0){
				userRoleDao.addUserRole(transaction, userDto.getId(), userDto.getRoleList());
			}
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}


	public void deleteDoctor(Transaction transaction, String id) throws IOException {
		PreparedStatement prepareStatement = null;
		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(DELETE_DOCTOR);
			prepareStatement.setString(1, id);
			prepareStatement.executeUpdate();
			userRoleDao.deleteUserRole(transaction, id);
			DoctorDto d = map2.remove(id);
			if (d != null) {
				map.remove(d.getSeq());
				allItems.remove(d);
			}
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}

	private static final String GET_ALL = "select seq, id, password, name, gender, department_id, " +
			"degree, university, work_type, work_domain, introduction, birth_date, join_hospital_date " +
			"from s_users order by seq";
//	private static final String GET_BY_ID = "select seq, id, password, name, gender, department_id, " +
//			"degree, university, work_type, work_domain, introduction, birth_date, join_hospital_date " +
//			"from s_users where id = ? order by seq";
//	private static final String GET_BY_SEQ = "select seq, id, password, name, gender, department_id, " +
//			"degree, university, work_type, work_domain, introduction, birth_date, join_hospital_date " +
//			"from s_users where seq = ? order by seq";
//	private static final String GET_BY_OFFICE = "select seq, id, password, name, gender, department_id, " +
//			"degree, university, work_type, work_domain, introduction, birth_date, join_hospital_date " +
//			"from s_users where department_id = ? order by seq";
//	private static final String INSERT_DOCTOR = "insert into s_users (seq, id, password, name, gender, department_id, " +
//			"degree, university, work_type, work_domain, introduction, birth_date, join_hospital_date) values (seq_doctor.nextVal, " +
//			"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

	private static final String INSERT_DOCTOR = "insert into s_users (seq, id, password, name, gender, department_id, " +
			"degree, university, work_type, work_domain, introduction, birth_date, join_hospital_date) values ( " +
			"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
	private static final String UPDATE_DOCTOR = "update s_users set password = ?, name = ?, gender = ?, department_id = ?, " +
			"degree = ?, university = ?, work_type= ?, work_domain= ?, introduction = ?, birth_date = ?, join_hospital_date = ?  where seq = ?";
	private static final String DELETE_DOCTOR = "delete from s_users where id = ?";

}
